package com.cst.security.authentication.interceptor;

import com.cst.security.authentication.accessDecisionManager.AccessDecisionManagerImpl;
import com.cst.security.authentication.filterInvocationSecurityMetadataSource.MyInvocationSecurityMetadataSourceService;
import com.cst.security.baseUtils.Exception.WithoutPermissionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.*;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;

import javax.servlet.*;
import java.io.IOException;
import java.util.Collection;

@Service
public class AuthorizationSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

	private final static Logger logger = LoggerFactory.getLogger(AuthorizationSecurityInterceptor.class);

	private FilterInvocationSecurityMetadataSource securityMetadataSource;
	private boolean observeOncePerRequest = true;

	//决策管理
	@Autowired
	AccessDecisionManager accessDecisionManager;
	@Autowired
	public void setMyAccessDecisionManager(AccessDecisionManagerImpl accessDecisionManager) {
		super.setAccessDecisionManager(accessDecisionManager);
	}



	public AuthorizationSecurityInterceptor() {
	}

	public void init(FilterConfig arg0) throws ServletException {
	}

	public void destroy() {
	}

	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		FilterInvocation fi = new FilterInvocation(request, response, chain);
		this.invoke(fi);
	}

	public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
		return this.securityMetadataSource;
	}

	public SecurityMetadataSource obtainSecurityMetadataSource() {
		return this.securityMetadataSource;
	}

	@Autowired
	public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) {
		this.securityMetadataSource = newSource;
	}

	public Class<?> getSecureObjectClass() {
		return FilterInvocation.class;
	}

	public void invoke(FilterInvocation fi) throws IOException, ServletException {
		/*
		if (fi.getRequest() != null && fi.getRequest().getAttribute("__spring_security_filterSecurityInterceptor_filterApplied") != null && this.observeOncePerRequest) {
			fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
		} else {
			if (fi.getRequest() != null) {
				fi.getRequest().setAttribute("__spring_security_filterSecurityInterceptor_filterApplied", Boolean.TRUE);
			}
			InterceptorStatusToken token = super.beforeInvocation(fi);

			try {
				fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
			} finally {
				super.finallyInvocation(token);
			}
			super.afterInvocation(token, (Object)null);
		}*/
		InterceptorStatusToken token = this.beforeInvocation(fi);
		try {
			fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
		} finally {
			this.finallyInvocation(token);
		}
		this.afterInvocation(token, (Object)null);
	}

	protected InterceptorStatusToken beforeInvocation(Object object) {
		logger.info(" The following code validation is accessible ");
		Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);
		if (attributes != null && !attributes.isEmpty()) {
			Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
			try {
				this.accessDecisionManager.decide(authentication, object, attributes);
			} catch (Exception e) {
				logger.info("-=没有权限=-");
				throw new WithoutPermissionException("没有权限",e);
			}
		}
		return null;
	}

	public boolean isObserveOncePerRequest() {
		return this.observeOncePerRequest;
	}

	public void setObserveOncePerRequest(boolean observeOncePerRequest) {
		this.observeOncePerRequest = observeOncePerRequest;
	}
}
